Spring WebFlux 学习指南

作者 小秦同学 发布于 2025-02-24
预计阅读时间 5 分钟
字数总计约 1.3k

Spring WebFlux 学习指南

1. WebFlux 概述

Spring WebFlux 是 Spring 5 引入的响应式编程框架,旨在提供非阻塞、事件驱动的 Web 应用开发能力。它基于 Reactive Streams 规范,可与 Reactor 框架配合使用,实现高并发和流式数据处理。
理解“流式”和“非阻塞”对系统性能和用户体验的提升是关键,尤其在 WebFlux 环境下,它们是优化并发能力的核心。

为了更好地体会这两者,我们可以通过以下几个方面的实际案例来理解:

非阻塞(Non-blocking): 非阻塞式编程意味着当程序执行某些操作(如数据库查询或外部服务调用)时,它不会阻塞当前线程的执行。相反,它会将当前任务交给事件循环线程,继续执行其他任务,当操作完成后再通知程序结果。这样做的优势是:可以在一个线程中同时处理多个请求,避免了传统阻塞方式下的线程等待,提高了系统的并发能力。

在传统的阻塞式编程中,我们可能会做如下操作:

1
2
3
4
public KnowledgeBase getKnowledge(String id) {
KnowledgeBase knowledge = repository.findById(id); // 阻塞操作,等查询完成才继续
return knowledge;
}

查询时整个线程被阻塞,直到查询完成返回结果。假设查询一个大数据集合或执行 AI 生成,这会导致服务器的线程被大量占用,造成延迟。

而在 WebFlux 中,这个操作会变成:

1
2
3
4
5
6
7
public Mono<KnowledgeBase> getKnowledge(String id) {
return repository.findById(id); // 这将是一个非阻塞操作,立即返回 Mono 对象
}

public Flux<String> generateAnswerStream(String question) {
return Flux.just("AI生成的第一部分...", "AI生成的第二部分...", "AI生成的第三部分...").delayElements(Duration.ofMillis(500)); // 每个部分延迟500ms返回
}

**非阻塞式 + 流式返回:**通过 WebFlux 和流式响应,我们可以将多个数据部分逐个返回,节省等待时间,提升系统并发能力。例如,在流式响应中,每部分返回数据都会在 Mono 和 Flux 上“等待”直到有结果生成,线程不会阻塞,而是可以处理其他请求。这对于需要长时间生成或处理的数据非常有效,比如 AI 内容生成、实时数据推送等。

2. Mono 与 Flux

WebFlux 主要依赖 Reactor 库,提供 MonoFlux 作为响应式编程的核心数据类型。

  • Mono:表示 0 或 1 个数据的流。
  • Flux:表示 0-N 个数据的流。

示例:

1
2
3
4
5
6
7
public Mono<String> getSingleData() {
return Mono.just("Hello, WebFlux");
}

public Flux<String> getMultipleData() {
return Flux.just("Data1", "Data2", "Data3");
}

2.WebFlux 与 Spring MVC 的区别

特性 Spring MVC Spring WebFlux
编程模型 基于 Servlet (阻塞) 基于 Reactive Streams (非阻塞)
线程模型 每个请求一个线程 事件驱动,少量线程处理高并发
支持的服务器 Tomcat, Jetty Netty, Undertow, Tomcat, Jetty
适用场景 传统 Web 应用 高并发、高吞吐、流式数据处理

官方对 Spring MVC 的定义:

Spring MVC 构建于 Servlet API 之上,使用的是同步阻塞式 I/O 模型,什么是同步阻塞式 I/O 模型呢?就是说,每一个请求对应一个线程去处理

官方对 Spring WebFlux 的定义:

Spring WebFlux is a non-blocking web framework built from the ground up to take advantage of multi-core, next-generation processors and handle massive numbers of concurrent connections.

Spring WebFlux 是一个异步非阻塞式的 Web 框架,它能够充分利用多核 CPU 的硬件资源去处理大量的并发请求

文档中有说到:WebFlux 并不能使接口的响应时间缩短,它仅仅能够提升吞吐量和伸缩性

那么它就特别适合应用在 IO 密集型的服务中,比如微服务网关这样的应用中。

PS: IO 密集型包括:磁盘IO密集型, 网络IO密集型

3.选 WebFlux 还是 Spring MVC?

Spring MVC 是同步阻塞的,普通的单个服务优先 Spring MVC

WebFlux 主要还是应用在异步非阻塞编程模型,如果服务中大量使用非同步方案,这时候才考虑 WebFlux 。

在微服务架构中,Spring MVC 和 WebFlux 可以混合使用(如上面说的网关)。

总结:WebFlux 不是 Spring MVC 的替代方案

4、非阻塞 + 流式与 SSE/WebSocket

SSE(Server-Sent Events)WebSocket 都可以用于 流式数据传输,而 WebFlux 提供了 非阻塞 的数据处理方式,因此 WebFlux 可以高效地与 SSE 和 WebSocket 结合使用。

结合 SSE 进行流式返回:

1
2
3
4
5
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamData() {
return Flux.just("数据1", "数据2", "数据3")
.delayElements(Duration.ofSeconds(1)); // 模拟数据流式返回
}

结合 WebSocket:

1
2
3
4
5
6
7
8
9
@Component
public class WebSocketHandlerImpl implements WebSocketHandler {
// WebSocket 处理器每秒给客户端推送一条消息,且是 非阻塞 的。
@Override
public Mono<Void> handle(WebSocketSession session) {
return session.send(Flux.interval(Duration.ofSeconds(1))
.map(i -> session.textMessage("消息 " + i)));
}
}

定义说明:

WebFlux 事件循环:同一个线程可以处理多个请求,遇到 I/O 操作(如数据库查询)时,释放线程继续处理其他请求,等 I/O 完成后通过回调恢复执行。


如果您觉得这篇博客对您有所帮助,欢迎分享给更多人。如果您发现博客中使用的图片存在版权问题,请及时联系作者,我们将尽快处理并删除相关内容。感谢您的支持!